package domainservice

import (
	"context"
	"time"

	"go-mall/common/enum"
	"go-mall/common/errcode"
	"go-mall/common/logger"
	"go-mall/common/util"
	"go-mall/dal/cache"
	"go-mall/logic/do"
)

type UserDomainSvc struct {
	ctx context.Context
}

func NewUserDomainSvc(ctx context.Context) *UserDomainSvc {
	return &UserDomainSvc{ctx: ctx}
}

func (us *UserDomainSvc) GetUserBaseInfo(userId int64) *do.UserBaseInfo {
	return &do.UserBaseInfo{
		ID:        12345678,
		Nickname:  "Kevin",
		LoginName: "kev@gomall.com",
		Verified:  1,
		Avatar:    "",
		Slogan:    "",
		IsBlocked: enum.UserBlockStateNormal,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
}

func (us *UserDomainSvc) GenAuthToken(userId int64,
	platform string, sessionId string,
) (*do.TokenInfo, error) {
	user := us.GetUserBaseInfo(userId)
	if user.GetID() == 0 || user.GetIsBlocked() == enum.UserBlockStateBlocked {
		err := errcode.ErrUserInvalid
		return nil, err
	}
	userSession := new(do.SessionInfo)
	userSession.UserId = userId
	userSession.Platform = platform
	if sessionId == "" {
		sessionId = util.GenSessionId(userId)
	}
	userSession.SessionId = sessionId
	accessToken, refreshToken, err := util.GenUserAuthToken(userId)
	userSession.AccessToken = accessToken
	userSession.RefreshToken = refreshToken
	if err != nil {
		err = errcode.Wrap("Token生成失败", err)
		return nil, err
	}
	err = cache.SetUserToken(us.ctx, userSession)
	if err != nil {
		errcode.Wrap("设置token缓存时发生错误", err)
		return nil, err
	}
	err = cache.DelOldSessionToken(us.ctx, userSession)
	if err != nil {
		errcode.Wrap("删除旧Token时发生错误", err)
		return nil, err
	}
	err = cache.SetUserSession(us.ctx, userSession)
	if err != nil {
		errcode.Wrap("设置session缓存时发生错误", err)
		return nil, err
	}

	tokenInfo := &do.TokenInfo{
		AccessToken:   userSession.AccessToken,
		RefreshToken:  userSession.RefreshToken,
		Duration:      int64(enum.AccessTokenDuration),
		SrvCreateTime: time.Now(),
	}
	return tokenInfo, nil
}

func (us *UserDomainSvc) RefreshToken(refreshToken string) (*do.TokenInfo, error) {
	log := logger.New(us.ctx)
	ok, err := cache.LockTokenRefresh(us.ctx, refreshToken)

	defer cache.UnlockTokenRefresh(us.ctx, refreshToken)
	if err != nil {
		err = errcode.Wrap("刷新Token时设置redis发生错误", err)
		return nil, err
	}

	if !ok {
		err = errcode.ErrTooManyRequests
		return nil, err
	}

	tokenSession, err := cache.GetRefreshToken(us.ctx, refreshToken)
	if err != nil {
		log.Error("GetRefreshToken Err", "err", err)
		err = errcode.ErrToken
		return nil, err
	}
	if tokenSession == nil || tokenSession.UserId == 0 {
		err = errcode.ErrToken
		return nil, err
	}
	userSession, err := cache.GetUserPlatformSession(us.ctx, tokenSession.UserId, tokenSession.Platform)
	if err != nil {
		log.Error("GetUserPlatformSession Err", "err", err)
		err = errcode.ErrToken
		return nil, err
	}
	if userSession.RefreshToken != refreshToken {
		log.Warn("ExiredRefreshToken",
			"requestToken", refreshToken,
			"newToken", userSession.RefreshToken,
			"userId", userSession.UserId,
		)
		err = errcode.ErrToken
		return nil, err
	}

	tokenInfo, err := us.GenAuthToken(tokenSession.UserId, tokenSession.Platform, tokenSession.SessionId)
	if err != nil {
		err = errcode.Wrap("GenAuthToken Err", err)
		return nil, err
	}
	return tokenInfo, nil
}
